<html> 
 
<head> 
<title>Blender to WebGL JavaScript exporter example</title> 
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> 
 
<script type="text/javascript" src="sylvester.js"></script> 
<script type="text/javascript" src="glUtils.js"></script>
<script type="text/javascript" src="blender-cube.js"></script>  
 
<script id="shader-fs" type="x-shader/x-fragment"> 
  varying vec2 vTextureCoord;
 
  uniform sampler2D uSampler;
 
  void main(void) {
    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
  }
</script> 
 
<script id="shader-vs" type="x-shader/x-vertex"> 
  attribute vec3 aVertexPosition;
  attribute vec2 aTextureCoord;
 
  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;
 
  varying vec2 vTextureCoord;
 
 
  void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vTextureCoord = aTextureCoord;
  }
</script> 
 
 
<script type="text/javascript"> 
 
  var gl;
  function initGL(canvas) {
    try {
      gl = canvas.getContext("experimental-webgl");
      gl.viewport(0, 0, canvas.width, canvas.height);
    } catch(e) {
    }
    if (!gl) {
      alert("Could not initialise WebGL. Do you have a WebGL enabled browser?");
    }
  }
 
 
  function getShader(gl, id) {
    var shaderScript = document.getElementById(id);
    if (!shaderScript) {
      return null;
    }
 
    var str = "";
    var k = shaderScript.firstChild;
    while (k) {
      if (k.nodeType == 3) {
        str += k.textContent;
      }
      k = k.nextSibling;
    }
 
    var shader;
    if (shaderScript.type == "x-shader/x-fragment") {
      shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (shaderScript.type == "x-shader/x-vertex") {
      shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
      return null;
    }
 
    gl.shaderSource(shader, str);
    gl.compileShader(shader);
 
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      alert(gl.getShaderInfoLog(shader));
      return null;
    }
 
    return shader;
  }
 
 
  var shaderProgram;
  function initShaders() {
    var fragmentShader = getShader(gl, "shader-fs");
    var vertexShader = getShader(gl, "shader-vs");
 
    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);
 
    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
      alert("Could not initialise shaders");
    }
 
    gl.useProgram(shaderProgram);
 
    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);
 
    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);
 
    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    shaderProgram.samplerUniform = gl.getUniformLocation(shaderProgram, "uSampler");
  }
 
 
  function handleLoadedTexture(texture) {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, texture.image, true);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.bindTexture(gl.TEXTURE_2D, null);
  }
 
 
  var neheTexture;
  function initTexture() {
    neheTexture = gl.createTexture();
    neheTexture.image = new Image();
    neheTexture.image.onload = function() {
      handleLoadedTexture(neheTexture)
    }
 
    neheTexture.image.src = "cube-texture.jpg";
  }
 
 
  var mvMatrix;
  var mvMatrixStack = [];
 
  function mvPushMatrix(m) {
    if (m) {
      mvMatrixStack.push(m.dup());
      mvMatrix = m.dup();
    } else {
      mvMatrixStack.push(mvMatrix.dup());
    }
  }
 
  function mvPopMatrix() {
    if (mvMatrixStack.length == 0) {
      throw "Invalid popMatrix!";
    }
    mvMatrix = mvMatrixStack.pop();
    return mvMatrix;
  }
 
  function loadIdentity() {
    mvMatrix = Matrix.I(4);
  }
 
 
  function multMatrix(m) {
    mvMatrix = mvMatrix.x(m);
  }
 
  function mvTranslate(v) {
    var m = Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4();
    multMatrix(m);
  }
 
  function mvRotate(ang, v) {
    var arad = ang * Math.PI / 180.0;
    var m = Matrix.Rotation(arad, $V([v[0], v[1], v[2]])).ensure4x4();
    multMatrix(m);
  }
 
  var pMatrix;
  function perspective(fovy, aspect, znear, zfar) {
    pMatrix = makePerspective(fovy, aspect, znear, zfar);
  }
 
 
  function setMatrixUniforms() {
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, new WebGLFloatArray(pMatrix.flatten()));
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, new WebGLFloatArray(mvMatrix.flatten()));
  }
 
 
  var cubeVertexPositionBuffer;
  var cubeVertexTextureCoordBuffer;
  var cubeVertexIndexBuffer;
  function initBuffers() {
    cubeVertexPositionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    vertices = BlenderExport.Cube.vertices;
    gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertices), gl.STATIC_DRAW);
    cubeVertexPositionBuffer.itemSize = 3;
    cubeVertexPositionBuffer.numItems = BlenderExport.Cube.vertices.length / 3;
 
    cubeVertexTextureCoordBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    var textureCoords = BlenderExport.Cube.texCoords;
    gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(textureCoords), gl.STATIC_DRAW);
    cubeVertexTextureCoordBuffer.itemSize = 2;
    cubeVertexTextureCoordBuffer.numItems = BlenderExport.Cube.texCoords.length / 2;
 
    cubeVertexIndexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    var cubeVertexIndices = BlenderExport.Cube.indices;
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new WebGLUnsignedShortArray(cubeVertexIndices), gl.STATIC_DRAW);
    cubeVertexIndexBuffer.itemSize = 1;
    cubeVertexIndexBuffer.numItems = BlenderExport.Cube.indices.length;
  }
 
 
  var xRot = 0;
  var yRot = 0;
  var zRot = 0;
  var frameCount = 0;
  var dirFlag = 1;
  
  function drawScene() {
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
 
 	frameCount += dirFlag
 
 	if(frameCount == BlenderExport.Cube.frames.length - 1)
 	{
 		dirFlag = -1;
 	}
 	else if(frameCount == 0)
 	{
 	 	dirFlag = 1;
 	}

    perspective(45, 1.0, 0.1, 100.0);
    loadIdentity();
 
    mvTranslate([0.0, 0.0, -50.0])
    
    mvRotate(xRot, [1, 0, 0]);
    mvRotate(yRot, [0, 1, 0]);
//    mvRotate(zRot, [0, 0, 1]);


    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    vertices = BlenderExport.Cube.frames[frameCount];
    gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(vertices), gl.STATIC_DRAW);

    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, cubeVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer);
    gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);
 
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, neheTexture);
    gl.uniform1i(shaderProgram.samplerUniform, 0);

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
    setMatrixUniforms();
    gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
  }
 
 
  var lastTime = 0;
  function animate() {
    var timeNow = new Date().getTime();
    if (lastTime != 0) {
      var elapsed = timeNow - lastTime;
 
      xRot += (90 * elapsed) / 1000.0;
      yRot += (90 * elapsed) / 1000.0;
      zRot += (90 * elapsed) / 1000.0;
    }
    lastTime = timeNow;
  }
 
 
  function tick() {
    drawScene();
    animate();
  }
 
 
  function webGLStart() {
    var canvas = document.getElementById("lesson05-canvas");
    initGL(canvas);
    initShaders();
    initBuffers();
    initTexture();
 
    gl.clearColor(1.0, 1.0, 1.0, 1.0);
 
    gl.clearDepth(1.0);
 
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);
 
    setInterval(tick, 40);
  }
 
 
 
</script> 
 
 
</head> 
 
 
<body onload="webGLStart();"> 
<h2>Blender to WebGL animation export</h2>
  <canvas id="lesson05-canvas" style="border: none;" width="1000" height="800"></canvas> 
 This code is a modified version of <a href="http://www.learningwebgl.com">http://www.learningwebgl.com</a> Lesson 5: <a href="http://learningwebgl.com/blog/?p=507">http://learningwebgl.com/blog/?p=507</a>
</body> 
 
</html> 